/****************************************************************************
 * (c) 2001 StreamBox Inc.  http://www.streambox.com/ 
 *
 * Division: Moscow Research Division
 * Project:  Tidy Scaling (video compression project)
 *
 * Contents: Filter-based scaling functions. Only ^2 scaling factor allowed.
 *           File contains 10-item fast filter implemntation.
 *
 * History:  26-Sep-2001 - Created by Smirnov K
 ****************************************************************************/
/**
 * \file scale_msk_f10.c
 *  File contains 10-item fast filter implemntation. 
 *  Filter coeficients {3 -2 -12 14 61 61 14 -12 -2 3}
 *  Functions:
 *  void ScaleChannelUpX2Filter10_2Vertical() 
 *  void ScaleChannelUpX2Filter10_2Horisontal()
 *  void ScaleChannelDownX2Filter10_2Vertical()
 *  void ScaleChannelDownX2Filter10_2Horisontal()
 */ 

#include "Scale_msk.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/*============================= ScaleChannelUpX2Filter10_2Vertical ==============================*/
/**
 * Scale UP Vertical Dimension of 2D channel. Functon returns image sizes (w)x(2h) 
 * \param in          [IN]  - pointer to input 2D channel
 * \param out         [OUT] - pointer to output 2D channel
 * \param w           [IN]  - in-channel width 
 * \param h           [IN]  - in-channel height
 * \retval - none
 */
void ScaleChannelUpX2Filter10_2Vertical(BYTE* in, BYTE* out, int w, int h)
{
	int w_in = w, h_in = h, w_out = w_in, h_out = h<<1, h_end = h_in-4;
    
	int i, j ,c0,c1,c2,c3,c4;
	BYTE* pIn, *pOut;

	pIn = in+w_in;
	pOut = out+w_out;

		for (i= 0; i<w_in; i++)
		{
			c0=pIn[i-w_in];
			c1=pIn[i];
			c2=pIn[i+w_in];
			c3=pIn[i+w_in*2];
			pOut[i-w_out]=  CLIP_F( (		  61*c0 + 14*c1 - 2*c2 + 36)/73 );
			pOut[i]=		CLIP_F( ( 14*c0 + 61*c1 - 12*c2 + 3*c3 + 33)/66 );
			pOut[i+w_out]=	CLIP_F( (-12*c0 + 61*c1 + 14*c2 - 2*c3 + 30)/61 );
		}


	for (j = 0; j<h_end; j++)
	{
	pIn  += w_in;
	pOut += w_out*2;

		for(i=0; i<w_in; i++) 
		{
			c0=pIn[i-w_in*2];
			c1=pIn[i-w_in];
			c2=pIn[i];
			c3=pIn[i+w_in];
		    c4=pIn[i+w_in*2];
			pOut[i      ]= CLIP_F( (-2*c0 + 14*c1 + 61*c2 - 12*c3 + 3*c4 + 32)>>6 );
			pOut[i+w_out]= CLIP_F( ( 3*c0 - 12*c1 + 61*c2 + 14*c3 - 2*c4 + 32)>>6 );
		}
	}

	pIn  += w_in;
	pOut += w_out*2*2;
	
		for(i=0; i<w_in; i++) 
		{
			c0=pIn[i-w_in*2];
			c1=pIn[i-w_in];
			c2=pIn[i];
			c3=pIn[i+w_in];
//		    c4=pIn[i+w_in*2]; // does not exist
			pOut[i-w_out*2]=	CLIP_F( (-2*c0 + 14*c1 + 61*c2 - 12*c3 + 30)/61 );
			pOut[i-w_out  ]=	CLIP_F( ( 3*c0 - 12*c1 + 61*c2 + 14*c3 + 33)/66 );
			pOut[i        ]=	CLIP_F( (-2*c1 + 14*c2 + 61*c3 + 36)/73 );
			pOut[i+w_out  ]=	CLIP_F( ( 3*c1 - 12*c2 + 61*c3 + 26)/52 );
			pOut[i+w_out*2]=	CLIP_F( (-2*c2 + 14*c3 + 61*c3 + 36)/73 );
		}
}

/*============================= ScaleChannelUpX2Filter10_2Horisontal ==============================*/
/**
 * Scale UP Horisontal Dimension of 2D channel.The Functon returns image sizes (2w)x(h)
 *
 * \param in          [IN]  - pointer to input 2D channel
 * \param out         [OUT] - pointer to output 2D channel
 * \param w           [IN]  - in-channel width 
 * \param h           [IN]  - in-channel height
 * \retval - none
 */
void ScaleChannelUpX2Filter10_2Horisontal(BYTE * in, BYTE * out, int w,int h)
{
	int w_in = w, h_in = h, w_out = w<<1, h_out = h_in, w_end = w_in-4;
  	int i, j;
    int c0,c1,c2,c3;
	BYTE *pIn, *pOut;

    for(j=0; j<h_in; j++) 
    {
		pIn = in+j*w_in;
		pOut = out+j*w_out;

			c0=pIn[0];
			c1=pIn[1];
			c2=pIn[2];
			c3=pIn[3];
			pOut[0]=  CLIP_F( (		    61*c0 + 14*c1 - 2*c2 + 36)/73 );
			pOut[1]=  CLIP_F( ( 14*c0 + 61*c1 - 12*c2 + 3*c3 + 33)/66 );
			pOut[2]=  CLIP_F( (-12*c0 + 61*c1 + 14*c2 - 2*c3 + 30)/61 );

		pOut +=3;

        for(i = 0; i<w_end; i++, pIn++, pOut+=2) 
        {
			pOut[0]= CLIP_F( (-2*pIn[0] + 14*pIn[1] + 61*pIn[2] - 12*pIn[3] + 3*pIn[4] + 32)>>6 );
			pOut[1]= CLIP_F( ( 3*pIn[0] - 12*pIn[1] + 61*pIn[2] + 14*pIn[3] - 2*pIn[4] + 32)>>6 );
        }

			c0=pIn[0];
			c1=pIn[1];
			c2=pIn[2];
			c3=pIn[3];
//		    c4=pIn[i+w_in*2]; // does not exist
			pOut[0]=	CLIP_F( (-2*c0 + 14*c1 + 61*c2 - 12*c3 + 30)/61 );
			pOut[1]=	CLIP_F( ( 3*c0 - 12*c1 + 61*c2 + 14*c3 + 33)/66 );
			pOut[2]=	CLIP_F( (-2*c1 + 14*c2 + 61*c3 + 36)/73 );
			pOut[3]=	CLIP_F( ( 3*c1 - 12*c2 + 61*c3 + 26)/52 );
			pOut[4]=	CLIP_F( (-2*c2 + 14*c3 + 61*c3 + 36)/73 );
	}
}



/*============================= ScaleChannelDownX2Filter10_2Vertical ==============================*/
/**
 * Scale DOWN Vertical Dimension of 2D channel. The Functon returns image sizes (w)x(h>>1)
 *
 * \param in          [IN]  - pointer to input one dimensional channels
 * \param out         [OUT] - pointer to output one dimensional channels
 * \param w           [IN]  - in-channel width 
 * \param h           [IN]  - in-channel height 
 * \retval - none
 */
void ScaleChannelDownX2Filter10_2Vertical(BYTE *in, BYTE *out, int w, int h)
{
	int w_in = w, w_out = w_in, h_in = h, h_out = h>>1, h_end = h_out-5;
	int i,j;
	BYTE * pIn, *pOut;

	pIn = in;
	pOut = out;


	for(i = 0; i<w_in; i++)
	{
	    pOut[i]=		CLIP_F( ( 61* pIn[i       ] 
								 +14* pIn[i+w_in  ] 
								 -12* pIn[i+w_in*2]
								 - 2* pIn[i+w_in*3] 
								 + 3* pIn[i+w_in*4] + 32)>>6 );

	    pOut[i+w_out]=	CLIP_F( (+61*(pIn[i+w_in*2] + pIn[i+w_in  ])  
								 +14*(pIn[i+w_in*3] + pIn[i       ])
								 -12* pIn[i+w_in*4] 
								 - 2* pIn[i+w_in*5] 
								 + 3* pIn[i+w_in*6] + 68)/139 );

	    pOut[i+w_out*2]= CLIP_F( (61*(pIn[i+w_in*4] + pIn[i+w_in*3]) 
								 +14*(pIn[i+w_in*5] + pIn[i+w_in*2]) 
								 -12*(pIn[i+w_in*6] + pIn[i+w_in  ]) 
			                     - 2*(pIn[i+w_in*7] + pIn[i       ])
								 + 3* pIn[i+w_in*8] + 62)/125 );
	}
                                  
	pIn = in + w_in;//in[1]
	pOut += 3*w_out;//out[3]

	for(j = 0; j<h_end; j++)
	{

		for(i=0; i<w_in; i++)
		{
		    pOut[i] = CLIP_F( ( 61* (pIn[i+w_in*4] + pIn[i+w_in*5]) 
							   +14* (pIn[i+w_in*3] + pIn[i+w_in*6])
							   -12* (pIn[i+w_in*2] + pIn[i+w_in*7]) 
							   - 2* (pIn[i+w_in  ] + pIn[i+w_in*8]) 
							   + 3* (pIn[i       ] + pIn[i+w_in*9]) +64)>>7 );
	    }
		pIn += w_in*2;
		pOut += w_out;
	}


	for(i = 0; i<w_in; i++)
	{
	    pOut[i]=		 CLIP_F( ( 61*(pIn[i+w_in*4] + pIn[i+w_in*5]) 
								  +14*(pIn[i+w_in*3] + pIn[i+w_in*6]) 
								  -12*(pIn[i+w_in*2] + pIn[i+w_in*7]) 
								  - 2*(pIn[i+w_in  ] + pIn[i+w_in*8]) 
								  + 3* pIn[i       ] + 62)/125 );

		pOut[i+w_out]=	CLIP_F( (  61*(pIn[i+w_in*6] + pIn[i+w_in*7]) 
								  +14*(pIn[i+w_in*5] + pIn[i+w_in*8]) 
								  -12* pIn[i+w_in*4] 
								  - 2* pIn[i+w_in*3] 
								  + 3* pIn[i+w_in*2] + 68)/139 );
	}
}                                                                            

/*============================= ScaleChannelDownX2Filter10_2Horisontal ==============================*/
/**
 * Scale DOWN Horisontal Dimension of 2D channel. The Functon returns image sizes (w>>1)x(h)
 *
 * \param in          [IN]  - pointer to input one dimensional channels
 * \param out         [OUT] - pointer to output one dimensional channels
 * \param w           [IN]  - in-channel width 
 * \param h           [IN]  - in-channel height 
 * \retval - none
 */
void ScaleChannelDownX2Filter10_2Horisontal(BYTE *in, BYTE *out, int w, int h)
{
	int w_in = w, w_out = w>>1, h_in = h, h_out = h_in, w_end = w_out-5;
	int i,j;
	BYTE * pIn, *pOut;


	for(j = 0; j<h_in; j++)

	{

		pIn = in+j*w_in;
		pOut = out+j*w_out;

	    pOut[0]=		CLIP_F( ( 61* pIn[0] 
								 +14* pIn[1] 
								 -12* pIn[2]
								 - 2* pIn[3] 
								 + 3* pIn[4] + 32)>>6 );

	    pOut[1]=		CLIP_F( (+61*(pIn[2] + pIn[1])  
								 +14*(pIn[3] + pIn[0])
								 -12* pIn[4] 
								 - 2* pIn[5] 
								 + 3* pIn[6] + 68)/139 );

	    pOut[2]=		CLIP_F( (+61*(pIn[4] + pIn[3]) 
								 +14*(pIn[5] + pIn[2]) 
								 -12*(pIn[6] + pIn[1]) 
			                     - 2*(pIn[7] + pIn[0])
								 + 3* pIn[8] + 62)/125 );
                                  
	pIn++;
	pOut += 3;

		for(i=0; i<w_end; i++, pIn+=2)
		{
		    pOut[i] = CLIP_F( ( 61* (pIn[4] + pIn[5]) 
							   +14* (pIn[3] + pIn[6])
							   -12* (pIn[2] + pIn[7]) 
							   - 2* (pIn[1] + pIn[8]) 
							   + 3* (pIn[0] + pIn[9]) +64)>>7 );
	    }

	pOut+=w_end;

	    pOut[0]= CLIP_F( ( 61*(pIn[4] + pIn[5]) 
						  +14*(pIn[3] + pIn[6]) 
						  -12*(pIn[2] + pIn[7]) 
						  - 2*(pIn[1] + pIn[8]) 
						  + 3* pIn[0] + 62)/125 );

		pOut[1]= CLIP_F( ( 61*(pIn[6] + pIn[7]) 
						  +14*(pIn[5] + pIn[8]) 
						  -12* pIn[4] 
						  - 2* pIn[3] 
						  + 3* pIn[2] + 68)/139 );
	}
}                                                                            



/************************  end of file **************************************/
